import { injectable, inject } from 'inversify';
import { IAuthService, LoginResult } from '../interfaces/IAuthService';
import { IUserService } from '../interfaces/IUserService';
import { User } from '../../domain/entities/user.entity';
import { Token } from '../../domain/entities/token.entity';
import { TYPES } from '../../infrastructure/ioc/types';
import { LoggerService } from '../../infrastructure/logging/logger.service';
import { ConfigService } from '../../infrastructure/config/config.service';
import { IRepository } from '../../infrastructure/database/repositories/interfaces/IRepository';
import {
  generateSalt,
  hashPassword,
  verifyPassword,
  generateToken,
  generateJwtToken,
  verifyJwtToken
} from '../../infrastructure/auth/auth.utils';

@injectable()
export class AuthService implements IAuthService {
  constructor(
    @inject(TYPES.UserService) private userService: IUserService,
    @inject(TYPES.TokenRepository) private tokenRepository: IRepository<Token>,
    @inject(TYPES.LoggerService) private logger: LoggerService,
    @inject(TYPES.ConfigService) private configService: ConfigService,
    @inject(TYPES.UserRepository) private userRepository: IRepository<User>
  ) {}

  async register(username: string, password: string, email?: string): Promise<User> {
    try {
      // 检查用户名是否已存在
      const existingUser = await this.userService.findByUsername(username);
      if (existingUser) {
        throw new Error('Username already exists');
      }

      // 如果提供了邮箱，检查邮箱是否已存在
      if (email) {
        const userWithEmail = await this.userService.findByEmail(email);
        if (userWithEmail) {
          throw new Error('Email already in use');
        }
      }

      // 生成盐值和哈希密码
      const salt = generateSalt();
      const hashedPassword = hashPassword(password, salt);

      // 创建新用户
      const userData: Partial<User> = {
        username,
        password: `${salt}:${hashedPassword}`, // 存储格式：盐值:哈希密码
        email,
        status: 'offline',
        role: 'user',
        permissions: [],
        isVerified: false
      };

      // 直接保存新用户而不是尝试更新
      return await this.userRepository.save(userData as User);
    } catch (error: any) {
      this.logger.error(`Registration error: ${error.message}`);
      throw error;
    }
  }

  async login(username: string, password: string): Promise<LoginResult> {
    try {
      // 查找用户
      const user = await this.userService.findByUsername(username);
      if (!user) {
        throw new Error('Invalid username or password');
      }

      // 验证密码
      const [salt, hashedPassword] = user.password.split(':');
      if (!verifyPassword(password, salt, hashedPassword)) {
        throw new Error('Invalid username or password');
      }

      // 更新用户状态和最后登录时间
      user.status = 'online';
      user.lastLogin = new Date();
      await this.userService.updateUser(user.id, user);

      // 生成访问令牌和刷新令牌
      const accessToken = await this.generateAccessToken(user);
      const refreshToken = await this.generateRefreshToken(user);

      return {
        user,
        accessToken,
        refreshToken
      };
    } catch (error: any) {
      this.logger.error(`Login error: ${error.message}`);
      throw error;
    }
  }

  async verifyToken(token: string): Promise<User | null> {
    try {
      // 解析JWT令牌
      const payload = verifyJwtToken(token, this.configService.getJwtSecret());
      if (!payload || !payload.userId) {
        return null;
      }

      // 查找用户
      return await this.userService.findById(payload.userId);
    } catch (error: any) {
      this.logger.error(`Token verification error: ${error.message}`);
      return null;
    }
  }

  async refreshToken(refreshToken: string): Promise<{ accessToken: string; refreshToken: string } | null> {
    try {
      // 在数据库中查找刷新令牌
      const tokenEntity = await this.tokenRepository.findOne({
        where: { token: refreshToken, type: 'refresh' }
      });

      if (!tokenEntity || new Date() > tokenEntity.expiresAt) {
        return null;
      }

      // 查找用户
      const user = await this.userService.findById(tokenEntity.userId);
      if (!user) {
        return null;
      }

      // 生成新令牌
      const newAccessToken = await this.generateAccessToken(user);
      const newRefreshToken = await this.generateRefreshToken(user);

      // 删除旧的刷新令牌
      await this.tokenRepository.delete(tokenEntity.id);

      return {
        accessToken: newAccessToken,
        refreshToken: newRefreshToken
      };
    } catch (error: any) {
      this.logger.error(`Token refresh error: ${error.message}`);
      return null;
    }
  }

  async changePassword(userId: string, oldPassword: string, newPassword: string): Promise<boolean> {
    try {
      // 查找用户
      const user = await this.userService.findById(userId);
      if (!user) {
        throw new Error('User not found');
      }

      // 验证旧密码
      const [salt, hashedPassword] = user.password.split(':');
      if (!verifyPassword(oldPassword, salt, hashedPassword)) {
        throw new Error('Incorrect old password');
      }

      // 生成新的盐值和哈希密码
      const newSalt = generateSalt();
      const newHashedPassword = hashPassword(newPassword, newSalt);

      // 更新密码
      user.password = `${newSalt}:${newHashedPassword}`;
      await this.userService.updateUser(userId, { password: user.password });

      // 使相关的所有令牌失效
      // 这里应该有一个删除用户所有令牌的方法，但为简单起见，我们跳过了这一步

      return true;
    } catch (error: any) {
      this.logger.error(`Change password error: ${error.message}`);
      return false;
    }
  }

  validatePermission(user: User, requiredPermission: string | string[]): boolean {
    // 如果用户是管理员，总是允许访问
    if (user.role === 'admin') {
      return true;
    }

    // 检查单个权限
    if (typeof requiredPermission === 'string') {
      return user.permissions.includes(requiredPermission);
    }

    // 检查多个权限（要求全部满足）
    return requiredPermission.every(perm => user.permissions.includes(perm));
  }

  // 辅助方法：生成访问令牌
  private async generateAccessToken(user: User): Promise<string> {
    const payload = {
      userId: user.id,
      username: user.username,
      role: user.role
    };

    // 生成JWT令牌
    return generateJwtToken(
      payload,
      this.configService.getJwtSecret(),
      this.configService.getAccessTokenExpiresIn()
    );
  }

  // 辅助方法：生成刷新令牌
  private async generateRefreshToken(user: User): Promise<string> {
    // 生成随机令牌
    const refreshToken = generateToken(64);

    // 计算过期时间
    const expiresAt = new Date();
    expiresAt.setSeconds(expiresAt.getSeconds() + this.configService.getRefreshTokenExpiresIn());

    // 保存令牌到数据库
    const tokenEntity = new Token();
    tokenEntity.userId = user.id;
    tokenEntity.token = refreshToken;
    tokenEntity.type = 'refresh';
    tokenEntity.expiresAt = expiresAt;

    await this.tokenRepository.save(tokenEntity);

    return refreshToken;
  }
}